#ifndef TCPCONNECTION_H
#define TCPCONNECTION_H

#include <map>
#include <string>
#include <boost/asio.hpp>
#include <boost/array.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include "database/Client.hpp"
#include "Protocol.h"

class TCPServer;
class TCPConnection;

class TCPConnection : public boost::enable_shared_from_this<TCPConnection>
{
 public:
  typedef CSProtocol::IData* (TCPConnection::*action)();
  typedef boost::shared_ptr<TCPConnection> pointer;
  static pointer create(boost::asio::io_service& ios);
  boost::asio::ip::tcp::socket& socket();
  void start(TCPServer *server);
  void read();
  void write(CSProtocol::Header &header, CSProtocol::IData &data);
  TCPServer *getServer() { return _server; }
  void setAuthenticate(const bool value) { _isAuthenticate = value; }
  bool getAuthenticate() const { return _isAuthenticate; }
  void setClient(Client *clt) { _client = clt; }
  Client *getClient() const { return _client; }

  CSProtocol::IData *createRegister() { return new CSProtocol::Register(); }
  CSProtocol::IData *createLogin() { return new CSProtocol::Login(); }
  CSProtocol::IData *createLogout() { return new CSProtocol::Logout(); }
  CSProtocol::IData *createAddContact() { return new CSProtocol::AddContact(); }
  CSProtocol::IData *createProfil() { return new CSProtocol::Profil(); }

 private:
  enum eReadMod
  {
    readingHeader,
    readingData
  };
  int _curReadSize;
  eReadMod _curReadingMod;
  TCPConnection(boost::asio::io_service& io_service);
  boost::asio::ip::tcp::socket _socket;
  boost::array<char, 2048> _bufferIn;
  void handleWrite(const boost::system::error_code& error);
  void handleRead(const boost::system::error_code& error,
		  std::size_t bytes_transferred);
  boost::asio::deadline_timer _timer;
  void close();
  std::map<int, action> _actions;
  void initActions();
  void setReadMod(eReadMod newMod, int size);
  CSProtocol::Header *_readingHeader;
  CSProtocol::IData *_readingData;
  Client *_client;
  TCPServer *_server;
  bool _isAuthenticate;
};

#endif
